#include "Particle.h"


namespace SimPhy
{


Particle::Particle(): m_damping(1.0), m_inverseMass(1.0)
{}

real Particle::getMass() const
{
    if (m_inverseMass <= 0.0)
        return REAL_MAX;
    else
        return ((real)1.0)/m_inverseMass;
}

void Particle::setMass(const real mass)
{
    if(mass>0.0)
        m_inverseMass = ((real)1.0)/mass;
}

real Particle::getInverseMass() const
{
    return m_inverseMass;
}

bool Particle::hasFiniteMass() const
{
  return (m_inverseMass > 0.0);
}

void Particle::setDamping(const real damping)
{
    m_damping=damping;
}

real Particle::getDamping() const
{
    return m_damping;
}


Vector3D Particle::getPosition() const
{
    return m_position;
}

void Particle::setPosition(const Vector3D &position)
{
    m_position=position;
}

Vector3D Particle::getVelocity() const
{
    return m_velocity;
}

void Particle::setVelocity(const Vector3D &velocity)
{
    m_velocity=velocity;
}

Vector3D Particle::getAcceleration() const
{
    return m_acceleration;
}

void Particle::setAcceleration(const Vector3D &acceleration)
{
    m_acceleration=acceleration;
}

Vector3D Particle::getForces() const
{
   return m_appliedForces;
}

void Particle::addForce(const Vector3D &force)
{
    m_appliedForces+=force;
}

void Particle::clearForces()
{
    m_appliedForces.zero();
}

void Particle::explicitEulerIntegrate(real timeStep)
{
    // We don't integrate things with zero inversemass.
    if (m_inverseMass <= 0.0) return;

    // Work out the acceleration from the force
    m_acceleration=m_appliedForces*m_inverseMass;

    // Update linear velocity from the acceleration.
    m_velocity=m_velocity+m_acceleration*timeStep;

    // Impose drag.
    m_velocity *= pow(m_damping, timeStep);

    // Update linear position.
    m_position=m_position+m_velocity*timeStep;

    clearForces();
}

real Particle::kineticEnergy() const
{
    return 0.5*getMass()*m_velocity.squaredLenght();
}

std::ostream& operator<<( std::ostream &stream, Particle const& particle )
{
    stream <<"Damping factor : " << particle.getDamping() << std::endl;
    stream <<"Mass : " << particle.getMass() << std::endl;
    stream <<"Position : " << particle.getPosition() << std::endl;
    stream <<"Velocity : " << particle.getVelocity() << std::endl;
    stream <<"Acceleration : " << particle.getAcceleration() << std::endl;
    stream <<"Applied force(s) : " << particle.getForces() << std::endl;

    return stream;
}


}
